tl;dr

This notebook determines the model framework utilized for this PRD. It utilizes the results from the hyperparameter tuning step, and trains the optimal model for each algorithm on the v67 dataset. The resultant predictions of these optimal models are compared to a v68 validation dataset. The framework used to generate the highest performant model (e.g., features, hyperparameters) will be used in online model training for the subsetting of Beta in production use.

Features

Feature sets:

  1. Only performance metrics.
  2. Performance metrics and the highest found by Boruta with original dataset.
  3. Performance metrics and the highest found by Boruta with equal labels dataset.
  4. Performance metrics and all covariates.
  5. Only the highest covariates found by Boruta (excluding performance).
  6. Only the highest covariates found by Boruta (equal labels, excluding performance).
  7. Utilize all covariates (excluding performance).

Validation Bootstraps

30 bootstrap replicates of v68 Release will be utilized to validate the models. There are 257697 profiles utilized for this purpose.

[1] "Loading previously created bootstraps from file"

Oversampling

The entire v67 dataset will be utilized for training. However, most of the matching algorithms are more performant with higher ratios of Beta to Release. Therefore, various levels of oversampled datasets are created for training. There are 70345 profiles utilized for this purpose.

[1] "Loading previously created oversampling training sets from file"

Model Training

Two matching methods were ultimately tested, as CEM and subclassing were producing extremely poor results.

  • nearest-neighbors
  • genetic matching

For all models the following diagnostics are reported:

  • mean, median score against the 30 validation replicates
  • Number of matched Beta samples
  • QQ and ridge plots of original and matched Beta samples

Nearest-Neighbors, Malahanobis

Hyperparameters: hyperparameter_tuning_nn_malahanobis.Rmd

Feature selection and hyperparameter tuning for the nearest-neighbors models were all trained using the MatchIt library. These models are trained using the full, relevantly oversampled, training dataset.

FS 1

  • caliper = 0.20
  • calcloset = TRUE
  • ratio = 2
  • replace = FALSE
  • 4x oversampling
       mean      median 
0.001665983 0.001671272 

Number of Beta samples: 29814

FS 3

  • caliper = 3.00
  • calcloset = TRUE
  • ratio = 1
  • replace = TRUE
  • 16x oversampling
       mean      median 
0.004966338 0.004966342 

Number of Beta samples: 3259

FS 5

  • caliper = 0
  • calcloset = TRUE
  • ratio = 1
  • replace = FALSE
  • 8x oversampling
       mean      median 
0.004599767 0.004598880 

Number of Beta samples: 6208

Nearest-Neighbors Logit, Linear

Hyperparameters: hyperparameter_tuning_nn_logit_linear.Rmd

FS 1

  • caliper = 0.4
  • calcloset = TRUE
  • ratio = 3
  • replace = FALSE
  • 4x oversampling
  • Interactions across covariates
       mean      median 
0.001789146 0.001795468 

Number of Beta samples: 44721

FS 5

  • caliper = 0
  • calcloset = FALSE
  • ratio = 1
  • replace = FALSE
  • 8x oversampling
       mean      median 
0.005422051 0.005421492 

Nearest-Neighbors GAM, Logit

Hyperparameters: hyperparameter_tuning_nn_gam_logit.Rmd

FS 1

  • caliper = 0.5
  • calcloset = FALSE
  • ratio = 3
  • replace = FALSE
  • 4x oversampling
  • Interactions across covariates
       mean      median 
0.003007450 0.003011005 

Number of Beta samples: 44721

FS 5

  • caliper = 0
  • calcloset = FALSE
  • ratio = 1
  • replace = FALSE
  • 4x oversampling
       mean      median 
0.006251073 0.006245329 

Number of Beta samples: 44721

Nearest-Neighbors Probit, Linear

Hyperparameters: hyperparameter_tuning_nn_probit_linear.Rmd

FS 1

  • caliper = 0.4
  • calcloset = FALSE
  • ratio = 3
  • replace = FALSE
  • 4x oversampling
  • Interactions across covariates
       mean      median 
0.001773316 0.001777554 

Number of Beta samples: 44721

FS 5

  • caliper = 0
  • calcloset = FALSE
  • ratio = 1
  • replace = FALSE
  • 8x oversampling
       mean      median 
0.004524079 0.004523233 

Number of Beta samples: 7453

Genetic Matching

Due to the very long training times of genetic matching, feature selection and hyperparameter tuning were not performed using bootstrap sampes. The models were previously trained using the full training sample. The resultant match beta subsets were serialized and uploaded to GCP.

Trained: feature_selection_genmatch_linear.Rmd

Successfully auto-authenticated via moz-fx-dev-cdowhyglund-subBeta-788f8f0d4627.json
Set default bucket name to 'moz-fx-dev-subbeta'
2019-11-21 07:57:28 -- Saved data/milestone2/feature_selection_genmatch_.RData to data/feature_selection_genmatch_.RData (166.4 Mb)
[1] TRUE

FS 1

       mean      median 
0.001500821 0.001506689 

Number of Beta samples: 44985

Pop.Size 500

       mean      median 
0.001547905 0.001553225 

Number of Beta samples: 44982

FS 3

       mean      median 
0.003216196 0.003224829 

Number of Beta samples: 44982

FS 5

       mean      median 
0.003283770 0.003288647 

Number of Beta samples: 44982

Results

Genetic matching produces the optimal matching results. It yields the lowest scores, without dropping large sample of the Beta profiles. Unsurprisingly, matching directly, and only, on the performance metrics yields the best results. Increasing the population size hyperparameter slightly decreased model performance, which is surprising. Considering this substantially increases training times, the lower value will be used.

Conclusion: Optimal model framework

  • matching algorithm: Genetic Matching
  • features: Only performance metrics
  • hyperparameters: Default for Matching library

Push to GCP

The boostrap replicates for validation, oversampled traininig datasets, resultant quantile calculations, and matched datasets are saved to an R image. Then uploaded to the project GCP bucket.

[1] "Previously trained results already exist: data/milestone2/validation_results_20191106.RData"
LS0tCnRpdGxlOiAnTWlsZXN0b25lIDI6IE1vZGVsIFZhbGlkYXRpb24nCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwpkYXRlOiAnTGFzdCBVcGRhdGVkOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgIiVCICVkLCAlWSIpYCcKLS0tCgojIHRsO2RyIApUaGlzIG5vdGVib29rIGRldGVybWluZXMgdGhlIFttb2RlbCBmcmFtZXdvcmtdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL2RvY3VtZW50L2QvMVNmdWFudm1ZbXZtRUZBZFE3WjVkakRlTGV6ZE5CMVRFU3FWbWo5M084dG8vZWRpdCNoZWFkaW5nPWguZXgza2s3emQ1YTF5KSB1dGlsaXplZCBmb3IgdGhpcyBbUFJEXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9kb2N1bWVudC9kLzFZZ3o2TWt1ZFlIWmpuRG5EOVo5N2tVeUZydlYzS0dXc2pYeVBqZGRoSHEwL2VkaXQjaGVhZGluZz1oLmx2YjlsOGd3Mm5lZSkuIEl0IHV0aWxpemVzIHRoZSByZXN1bHRzIGZyb20gdGhlIGh5cGVycGFyYW1ldGVyIHR1bmluZyBzdGVwLCBhbmQgdHJhaW5zIHRoZSBvcHRpbWFsIG1vZGVsIGZvciBlYWNoIGFsZ29yaXRobSBvbiB0aGUgdjY3IGRhdGFzZXQuIFRoZSByZXN1bHRhbnQgcHJlZGljdGlvbnMgb2YgdGhlc2Ugb3B0aW1hbCBtb2RlbHMgYXJlIGNvbXBhcmVkIHRvIGEgdjY4IHZhbGlkYXRpb24gZGF0YXNldC4gVGhlIGZyYW1ld29yayB1c2VkIHRvIGdlbmVyYXRlIHRoZSBoaWdoZXN0IHBlcmZvcm1hbnQgbW9kZWwgKGUuZy4sIGZlYXR1cmVzLCBoeXBlcnBhcmFtZXRlcnMpIHdpbGwgYmUgdXNlZCBpbiBvbmxpbmUgbW9kZWwgdHJhaW5pbmcgZm9yIHRoZSBzdWJzZXR0aW5nIG9mIEJldGEgaW4gcHJvZHVjdGlvbiB1c2UuCgpgYGB7ciwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0Kc291cmNlKCcuLi9saWIvc3VwcG9ydGluZ19mdW5jcy5SJykKc291cmNlKCcuLi9saWIvc2NvcmluZy5SJykKbGlicmFyeShNYXRjaEl0KQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ2dyaWRnZXMpCmxpYnJhcnkodmlyaWRpcykKYGBgCgpgYGB7ciBkYXRhX2xvYWQsIGVjaG89RkFMU0V9CmZpbGVfbmFtZSA9ICdkZl90cmFpbl92YWxpZGF0ZV8yMDE5MTAyNS5SRGF0YScKaW1hZ2VfZmlsZV9wYXRoID0gZmlsZS5wYXRoKCdkYXRhJywgZmlsZV9uYW1lKQoKIyBQdWxsIGZyb20gR0NQIGlmIG5lY2Vzc2FyeQppZiAoIWZpbGUuZXhpc3RzKGltYWdlX2ZpbGVfcGF0aCkpewogIFN5cy5zZXRlbnYoIkdDU19ERUZBVUxUX0JVQ0tFVCIgPSAibW96LWZ4LWRldi1zdWJiZXRhIiwKICAgICAgICAgICAiR0NTX0FVVEhfRklMRSIgPSAibW96LWZ4LWRldi1jZG93aHlnbHVuZC1zdWJCZXRhLTc4OGY4ZjBkNDYyNy5qc29uIikKICBsaWJyYXJ5KGdvb2dsZUNsb3VkU3RvcmFnZVIpCiAgZ2NzX2dldF9vYmplY3QoZmlsZS5wYXRoKCdkYXRhJywgJ21pbGVzdG9uZTInLCBmaWxlX25hbWUpLCBzYXZlVG9EaXNrID0gaW1hZ2VfZmlsZV9wYXRoLCBvdmVyd3JpdGUgPSBUUlVFKQp9Cgpsb2FkKGltYWdlX2ZpbGVfcGF0aCkKYGBgCgpgYGB7ciB2YXJfZGVmLCBlY2hvPUZBTFNFfQpkZl9yZWxfdmFsIDwtIGRmX3ZhbGlkYXRlX2YgJT4lCiAgZmlsdGVyKGxhYmVsID09ICdyZWxlYXNlJykKCmRmX2JldGFfdHJhaW4gPC0gZGZfdHJhaW5fZiAlPiUgZmlsdGVyKGlzX3JlbGVhc2UgPT0gRkFMU0UpCmRmX2JldGFfdmFsIDwtIGRmX3ZhbGlkYXRlX2YgJT4lIGZpbHRlcihpc19yZWxlYXNlID09IEZBTFNFKQpkZl9yZWxfdHJhaW4gPC0gZGZfdHJhaW5fZiAlPiUgZmlsdGVyKGlzX3JlbGVhc2UgPT0gVFJVRSkKbl9iZXRhIDwtIG5yb3coZGZfYmV0YV92YWwpCmBgYAoKIyBGZWF0dXJlcwpGZWF0dXJlIHNldHM6IAoKMS4gT25seSBwZXJmb3JtYW5jZSBtZXRyaWNzLgoyLiBQZXJmb3JtYW5jZSBtZXRyaWNzIGFuZCB0aGUgaGlnaGVzdCBmb3VuZCBieSBCb3J1dGEgd2l0aCBvcmlnaW5hbCBkYXRhc2V0LgozLiBQZXJmb3JtYW5jZSBtZXRyaWNzIGFuZCB0aGUgaGlnaGVzdCBmb3VuZCBieSBCb3J1dGEgd2l0aCBlcXVhbCBsYWJlbHMgZGF0YXNldC4KNC4gUGVyZm9ybWFuY2UgbWV0cmljcyBhbmQgYWxsIGNvdmFyaWF0ZXMuCjUuIE9ubHkgdGhlIGhpZ2hlc3QgY292YXJpYXRlcyBmb3VuZCBieSBCb3J1dGEgKGV4Y2x1ZGluZyBwZXJmb3JtYW5jZSkuCjYuIE9ubHkgdGhlIGhpZ2hlc3QgY292YXJpYXRlcyBmb3VuZCBieSBCb3J1dGEgKGVxdWFsIGxhYmVscywgZXhjbHVkaW5nIHBlcmZvcm1hbmNlKS4KNy4gVXRpbGl6ZSBhbGwgY292YXJpYXRlcyAoZXhjbHVkaW5nIHBlcmZvcm1hbmNlKS4gCgoKYGBge3IgYm9ydXRhX2ltcG9ydCwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZmlsZV9uYW1lID0gJ2ZlYXR1cmVfc2VsZWN0aW9uX2JvcnV0YV9pbml0aWFsXzIwMTkxMDIzLlJEYXRhJwppbWFnZV9maWxlX3BhdGggPSBmaWxlLnBhdGgoJ2RhdGEnLCBmaWxlX25hbWUpCgppZiAoIWZpbGUuZXhpc3RzKGltYWdlX2ZpbGVfcGF0aCkpewogIFN5cy5zZXRlbnYoIkdDU19ERUZBVUxUX0JVQ0tFVCIgPSAibW96LWZ4LWRldi1zdWJiZXRhIiwKICAgICAgICAgICAiR0NTX0FVVEhfRklMRSIgPSAibW96LWZ4LWRldi1jZG93aHlnbHVuZC1zdWJCZXRhLTc4OGY4ZjBkNDYyNy5qc29uIikKICBsaWJyYXJ5KGdvb2dsZUNsb3VkU3RvcmFnZVIpCiAgZ2NzX2dldF9vYmplY3QoZmlsZS5wYXRoKCdkYXRhJywgJ21pbGVzdG9uZTInLCBmaWxlX25hbWUpLCBzYXZlVG9EaXNrID0gaW1hZ2VfZmlsZV9wYXRoLCBvdmVyd3JpdGUgPSBUUlVFKQp9CmxvYWQoaW1hZ2VfZmlsZV9wYXRoKQpgYGAKCmBgYHtyIGJvcnV0YV9mcywgZWNobz1GQUxTRX0KZXh0cmFjdF9ib3J1dGFfZnMgPC0gZnVuY3Rpb24oYm9ydXRhX3JlcywgbnVtPTUpewogIGZlYXR1cmVzIDwtIE5VTEwKICBmb3IobWV0cmljIGluIG5hbWVzKGJvcnV0YV9yZXN1bHRzKSl7CiAgICBmZWF0dXJlcyA8LSBjKG5hbWVzKHNvcnQoYXBwbHkoYm9ydXRhX3Jlc1tbbWV0cmljXV0kSW1wSGlzdG9yeSwgMiwgbWVkaWFuKSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6bnVtXSksIGZlYXR1cmVzKQogIH0KICByZXR1cm4oc29ydCh1bmlxdWUoZmVhdHVyZXMpKSkKfQoKZmVhdHVyZXNfdG9wMTAgPC0gZXh0cmFjdF9ib3J1dGFfZnMoYm9ydXRhX3Jlc3VsdHMsIG51bT0xMCkKZmVhdHVyZXNfdG9wMTBfZXEgPC0gZXh0cmFjdF9ib3J1dGFfZnMoYm9ydXRhX3Jlc3VsdHNfZXEsIG51bT0xMCkKCiMgZmlsdGVyIG91dCBjYXRlZ29yaWNhbApmZWF0dXJlc190b3AxMCA8LSBkZl90cmFpbl9mICU+JSAKICBzZWxlY3QoZmVhdHVyZXNfdG9wMTApICU+JSAKICBzZWxlY3RfaWYoaXMubnVtZXJpYykgJT4lIAogIG5hbWVzKCkKZmVhdHVyZXNfdG9wMTBfZXEgPC0gZGZfdHJhaW5fZiAlPiUgCiAgc2VsZWN0KGZlYXR1cmVzX3RvcDEwX2VxKSAlPiUgCiAgc2VsZWN0X2lmKGlzLm51bWVyaWMpICU+JSAKICBuYW1lcygpCmBgYAoKYGBge3IgZmVhdHVyZV9zZXRzLCBlY2hvPUZBTFNFfQpwZXJmX21ldHJpY3MgPC0gbmFtZXMoZ2V0X20yX21ldHJpY19tYXAoKSkKCmNvdnMgPC0gZGZfdHJhaW5fZiAlPiUKICBzZWxlY3QoLXBlcmZfbWV0cmljcykgJT4lCiAgc2VsZWN0KC1jb250ZW50X2NyYXNoZXMpICU+JQogIHNlbGVjdCgtY2xpZW50X2lkKSAlPiUKICBzZWxlY3QoLWxhYmVsKSAlPiUKICBzZWxlY3QoLWlzX3JlbGVhc2UpICU+JQogIHNlbGVjdCgtYXBwX3ZlcnNpb24pICU+JQogIHNlbGVjdF9pZihpcy5udW1lcmljKSAlPiUgIyBNYWhhbGFub2JpcyBjb25zdHJhaW50CiAgbmFtZXMoKQoKZnMxIDwtIHBlcmZfbWV0cmljcwpmczIgPC0gYyhuYW1lcyhmczEpLCBmZWF0dXJlc190b3AxMCkKZnMzIDwtIGMobmFtZXMoZnMxKSwgZmVhdHVyZXNfdG9wMTBfZXEpCmZzNCA8LSBjKG5hbWVzKGZzMSksIGNvdnMpCmZzNSA8LSBmZWF0dXJlc190b3AxMApmczYgPC0gZmVhdHVyZXNfdG9wMTBfZXEKZnM3IDwtIGNvdnMKYGBgCgojIFZhbGlkYXRpb24gQm9vdHN0cmFwcwoKMzAgYm9vdHN0cmFwIHJlcGxpY2F0ZXMgb2YgdjY4IFJlbGVhc2Ugd2lsbCBiZSB1dGlsaXplZCB0byB2YWxpZGF0ZSB0aGUgbW9kZWxzLiBUaGVyZSBhcmUgYHIgbnJvdyhkZl9yZWxfdmFsKWAgcHJvZmlsZXMgdXRpbGl6ZWQgZm9yIHRoaXMgcHVycG9zZS4gCgpgYGB7ciBidHNfdmFsaWRhdGUsIGVjaG89RkFMU0V9CiMgY3JlYXRlIG9uY2UKZmlsZV9uYW1lID0gJ3ZhbGlkYXRpb25fYnRzXzIwMTkxMTA2LlJEYXRhJwpidHNfZmlsZV9wYXRoID0gZmlsZS5wYXRoKCdkYXRhJywgZmlsZV9uYW1lKQoKaWYgKCFmaWxlLmV4aXN0cyhidHNfZmlsZV9wYXRoKSl7CiAgcHJpbnQoJ0NyZWF0aW5nIHZhbGlkYXRpb24gYm9vdHN0cmFwcyBhbmQgc2F2aW5nJykKICBidHMgPSBsaXN0KCkKICBmb3IoaSBpbiAxOjMwKXsKICAgIGJ0c1tbaV1dIDwtIGRmX3JlbF92YWwgJT4lIAogICAgICBzYW1wbGVfZnJhYyhzaXplID0gMSwgcmVwbGFjZSA9IFRSVUUpICU+JQogICAgICBwdWxsKGNsaWVudF9pZCkgCiAgfQogIHNhdmUoYnRzLCBmaWxlID0gYnRzX2ZpbGVfcGF0aCkKfSBlbHNlIHsKICBwcmludCgnTG9hZGluZyBwcmV2aW91c2x5IGNyZWF0ZWQgYm9vdHN0cmFwcyBmcm9tIGZpbGUnKQogIGxvYWQoYnRzX2ZpbGVfcGF0aCkKfQpgYGAKCmBgYHtyIHNjb3JlciwgZWNobz1GQUxTRX0Kc2NvcmVfbW9kZWwgPC0gZnVuY3Rpb24oYnRzLCBkZl9tYXRjaCwgZGZfdmFsLCB3b3JrZXJzKXsKICBpZiAobWlzc2luZyh3b3JrZXJzKSkgd29ya2VycyA9IGRldGVjdENvcmVzKCkKICBjbCA8LSBtYWtlUFNPQ0tjbHVzdGVyKHdvcmtlcnMpIAogIHJlZ2lzdGVyRG9QYXJhbGxlbChjbCkKICBmaW5hbCA8LSB0cnlDYXRjaCh7CiAgICBzY29yZXMgPC0gZm9yZWFjaChpPTE6bGVuZ3RoKGJ0cyksIAogICAgICAgICAgICAgICAgICAgICAgLnBhY2thZ2VzID0gYygnZHBseXInLCAndHJhbnNwb3J0JyksIAogICAgICAgICAgICAgICAgICAgICAgLmV4cG9ydD1jKCdjYWxjX3Njb3JlJywgJ2NhbGNfY21zJywgJ2dldF9tMl9tZXRyaWNfbWFwJykpICVkb3BhciUgewogICAgICAgICAgICAgICAgICAgICAgICBidCA8LSBidHNbW2ldXQogICAgICAgICAgICAgICAgICAgICAgICB0ZXN0IDwtIGRmX3ZhbCAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHRfam9pbihkYXRhLmZyYW1lKGNsaWVudF9pZCA9IGJ0LCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSwgYnk9J2NsaWVudF9pZCcsICdyaWdodCcpCiAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICBkZl9zY29yZXMgPC0gdGVzdCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoZGZfbWF0Y2gpCiAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICBzY29yZSA8LSBjYWxjX3Njb3JlKGRmX3Njb3JlcywgZ2V0X20yX21ldHJpY19tYXAoKSkKICAgICAgICAgICAgICAgICAgICAgICAgc2NvcmUKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgc2NvcmVzIDwtIHVubGlzdChzY29yZXMpCiAgICBjKG1lYW4gPSBtZWFuKHNjb3JlcyksIG1lZGlhbiA9IG1lZGlhbihzY29yZXMpKQogIH0sIAogIGVycm9yID0gZnVuY3Rpb24oY29uZCl7CiAgICBtZXNzYWdlKHBhc3RlKCJCb290c3RyYXAgdmFsaWRhdGlvbiBmYWlsZWQ6ICIsIGNvbmQpKQogICAgcmV0dXJuKE5BKQogIH0sCiAgZmluYWxseSA9IHsKICAgIHN0b3BDbHVzdGVyKGNsKQogIH0KICApCiAgcmV0dXJuKGZpbmFsKQp9CgpidWlsZF9xdWFudGlsZV9kZiA8LSBmdW5jdGlvbih2YWxpZGF0aW9uLCBtYXRjaGVkLCBvcmlnaW5hbCl7CiAgcXFzIDwtIGxpc3QoKQogIGZvciAocGVyZl9tZXRyaWMgaW4gcGVyZl9tZXRyaWNzKXsKICAgIHFxIDwtIHFxcGxvdCh2YWxpZGF0aW9uW1twZXJmX21ldHJpY11dLCBtYXRjaGVkW1twZXJmX21ldHJpY11dLCBwbG90Lml0ID0gRkFMU0UpICU+JSAKICAgICAgYmluZF9yb3dzKCkgJT4lCiAgICAgIG11dGF0ZSh0eXBlID0gJ21hdGNoZWQnKQogICAgcXFfZnVsbCA8LSBxcXBsb3QodmFsaWRhdGlvbltbcGVyZl9tZXRyaWNdXSwgb3JpZ2luYWxbW3BlcmZfbWV0cmljXV0sIHBsb3QuaXQgPSBGQUxTRSkgJT4lIAogICAgICBiaW5kX3Jvd3MoKSAlPiUKICAgICAgbXV0YXRlKHR5cGUgPSAnb3JpZ2luYWwnKSAlPiUKICAgICAgYmluZF9yb3dzKHFxKSAlPiUKICAgICAgbXV0YXRlKG1ldHJpYyA9IHBlcmZfbWV0cmljKQogICAgIyBxcV9mdWxsJG1ldHJpYyA8LSBwZXJmX21ldHJpYwogICAgcXFzW1twZXJmX21ldHJpY11dIDwtIHFxX2Z1bGwKICB9CiAgcXFfZGYgPC0gcXFzICU+JSBiaW5kX3Jvd3MoKSAlPiUgcmVuYW1lKHJlbGVhc2UgPSB4LCBiZXRhID0geSkKICByZXR1cm4ocXFfZGYpCn0KCnBsb3RfdmFsaWRhdGlvbl9yZXN1bHRzIDwtIGZ1bmN0aW9uKHZhbGlkYXRpb24sIG1hdGNoZWQsIG9yaWdpbmFsLCBxcV9kZil7CiAgaWYgKG1pc3NpbmcocXFfZGYpKSBxcV9kZiA8LSBidWlsZF9xdWFudGlsZV9kZih2YWxpZGF0aW9uLCBtYXRjaGVkLCBvcmlnaW5hbCkKICAKICBkZiA8LSBtYXRjaGVkICU+JQogICAgICBtdXRhdGUobGFiZWwgPSAnYmV0YSAtIG1hdGNoZWQnKSAlPiUKICAgICAgYmluZF9yb3dzKHZhbGlkYXRpb24pICU+JQogICAgICBiaW5kX3Jvd3Mob3JpZ2luYWwpICU+JQogICAgICBzZWxlY3QocGVyZl9tZXRyaWNzLCBsYWJlbCkgIyAlPiUKICAgICAgIyBnYXRoZXIoa2V5ID0gJ21ldHJpYycsIHZhbHVlID0gJ21lYXN1cmVtZW50JywgLWxhYmVsKQogIAogIHBsb3RzIDwtIGxpc3QoKQogIGZvciAocG1ldCBpbiBwZXJmX21ldHJpY3MpewogICAgcF9xcSA8LSBnZ3Bsb3QocXFfZGYgJT4lIGZpbHRlcihtZXRyaWMgPT0gcG1ldCksIGFlcyh4ID0gcmVsZWFzZSwgeSA9IGJldGEpKSArCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gdHlwZSwgc2hhcGUgPSB0eXBlKSkgKyAKICAgICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArIAogICAgICB0aGVtZV9idygpICsgCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjIpKSArIAogICAgICBnZ3RpdGxlKHBtZXQpIAogICAgCiAgICBwX3JpZGdlIDwtIGdncGxvdChkZiwgYWVzKHg9ISFzeW0ocG1ldCksIHk9bGFiZWwsIGZpbGw9ZmFjdG9yKC4ucXVhbnRpbGUuLikpKSArCiAgICBzdGF0X2RlbnNpdHlfcmlkZ2VzKAogICAgICBnZW9tID0gImRlbnNpdHlfcmlkZ2VzX2dyYWRpZW50IiwgY2FsY19lY2RmID0gVFJVRSwKICAgICAgcXVhbnRpbGVzID0gMTAsIHF1YW50aWxlX2xpbmVzID0gVFJVRQogICAgKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBuYW1lID0gIlF1YXJ0aWxlcyIpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB4bGFiKHBtZXQpICsgCiAgICAgIHhsaW0oYygwLCAxMDAwMCkpICsgCiAgICAgIGd1aWRlcyhmaWxsID0gRkFMU0UpCiAgICAKICAgIHBsb3RzW1twYXN0ZShwbWV0LCAncXEnLCBzZXA9Il8iKV1dIDwtIHBfcXEKICAgIHBsb3RzW1twYXN0ZShwbWV0LCAncmlkZ2UnLCBzZXA9Il8iKV1dIDwtIHBfcmlkZ2UKICB9CiAgCiAgcHJpbnQocGxvdF9ncmlkKHBsb3RsaXN0ID0gcGxvdHMsIG5jb2wgPSAyKSkKfQpgYGAKCiMgT3ZlcnNhbXBsaW5nCgpUaGUgZW50aXJlIHY2NyBkYXRhc2V0IHdpbGwgYmUgdXRpbGl6ZWQgZm9yIHRyYWluaW5nLiBIb3dldmVyLCBtb3N0IG9mIHRoZSBtYXRjaGluZyBhbGdvcml0aG1zIGFyZSBtb3JlIHBlcmZvcm1hbnQgd2l0aCBoaWdoZXIgcmF0aW9zIG9mIEJldGEgdG8gUmVsZWFzZS4gVGhlcmVmb3JlLCB2YXJpb3VzIGxldmVscyBvZiBvdmVyc2FtcGxlZCBkYXRhc2V0cyBhcmUgY3JlYXRlZCBmb3IgdHJhaW5pbmcuIFRoZXJlIGFyZSBgciBuX2JldGFgIHByb2ZpbGVzIHV0aWxpemVkIGZvciB0aGlzIHB1cnBvc2UuCgpgYGB7ciBvdmVyc2FtcGxpbmcsIGVjaG89RkFMU0V9CiMgY3JlYXRlIG9uY2UKCmZpbGVfbmFtZSA9ICd0cmFpbmluZ19maW5hbF9vdmVyc2FtcGxlc18yMDE5MTEwNi5SRGF0YScKb3ZlcnNhbXBsZXNfZmlsZV9wYXRoID0gZmlsZS5wYXRoKCdkYXRhJywgZmlsZV9uYW1lKQoKaWYgKCFmaWxlLmV4aXN0cyhvdmVyc2FtcGxlc19maWxlX3BhdGgpKXsKICBwcmludCgnQ3JlYXRpbmcgb3ZlcnNhbXBsaW5nIHRyYWluaW5nIHNldHMgYW5kIHNhdmluZycpCiAgb3ZlcnNhbXBsZSA8LSBmdW5jdGlvbihvdmVyc2FtcGxpbmcsIGRmX2JldGEsIGRmX3JlbCkgewogICAgZGZfeCA8LSBkZl9yZWwgJT4lCiAgICAgIHNhbXBsZV9uKHNpemUgPSByb3VuZChuX2JldGEgLyBvdmVyc2FtcGxpbmcpKSAlPiUKICAgICAgcmJpbmQoZGZfYmV0YSkKICAgIHJldHVybihkZl94KQogICAgfQogIAogIG92ZXJzYW1wbGVzIDwtIGMoMSwgMiwgNCwgOCwgMTYpCiAgZGZzIDwtIGxhcHBseShvdmVyc2FtcGxlcywgb3ZlcnNhbXBsZSwgZGZfYmV0YSA9IGRmX2JldGFfdHJhaW4sIGRmX3JlbCA9IGRmX3JlbF90cmFpbikKICBuYW1lcyhkZnMpIDwtIGFzLmNoYXJhY3RlcihvdmVyc2FtcGxlcykKICBzYXZlKGRmcywgZmlsZSA9IG92ZXJzYW1wbGVzX2ZpbGVfcGF0aCkKfSBlbHNlIHsKICBwcmludCgnTG9hZGluZyBwcmV2aW91c2x5IGNyZWF0ZWQgb3ZlcnNhbXBsaW5nIHRyYWluaW5nIHNldHMgZnJvbSBmaWxlJykKICBsb2FkKG92ZXJzYW1wbGVzX2ZpbGVfcGF0aCkKfQpgYGAKCiMgTW9kZWwgVHJhaW5pbmcKClR3byBtYXRjaGluZyBtZXRob2RzIHdlcmUgdWx0aW1hdGVseSB0ZXN0ZWQsIGFzIENFTSBhbmQgc3ViY2xhc3Npbmcgd2VyZSBwcm9kdWNpbmcgZXh0cmVtZWx5IHBvb3IgcmVzdWx0cy4gCgoqIG5lYXJlc3QtbmVpZ2hib3JzCiogZ2VuZXRpYyBtYXRjaGluZwoKRm9yIGFsbCBtb2RlbHMgdGhlIGZvbGxvd2luZyBkaWFnbm9zdGljcyBhcmUgcmVwb3J0ZWQ6CgoqIG1lYW4sIG1lZGlhbiBzY29yZSBhZ2FpbnN0IHRoZSAzMCB2YWxpZGF0aW9uIHJlcGxpY2F0ZXMKKiBOdW1iZXIgb2YgbWF0Y2hlZCBCZXRhIHNhbXBsZXMKKiBRUSBhbmQgcmlkZ2UgcGxvdHMgb2Ygb3JpZ2luYWwgYW5kIG1hdGNoZWQgQmV0YSBzYW1wbGVzCgojIyBOZWFyZXN0LU5laWdoYm9ycywgTWFsYWhhbm9iaXMgCgpIeXBlcnBhcmFtZXRlcnM6IGBoeXBlcnBhcmFtZXRlcl90dW5pbmdfbm5fbWFsYWhhbm9iaXMuUm1kYAoKRmVhdHVyZSBzZWxlY3Rpb24gYW5kIGh5cGVycGFyYW1ldGVyIHR1bmluZyBmb3IgdGhlIG5lYXJlc3QtbmVpZ2hib3JzIG1vZGVscyB3ZXJlIGFsbCB0cmFpbmVkIHVzaW5nIHRoZSBgTWF0Y2hJdGAgbGlicmFyeS4gIFRoZXNlIG1vZGVscyBhcmUgdHJhaW5lZCB1c2luZyB0aGUgZnVsbCwgcmVsZXZhbnRseSBvdmVyc2FtcGxlZCwgdHJhaW5pbmcgZGF0YXNldC4gIAoKYGBge3IgdHJhaW5lciwgZWNobz1GQUxTRX0KdHJhaW5fbWF0Y2hpdCA8LSBmdW5jdGlvbih0cmFpbiwgbW9kZWxfY292cywgYWRkX2ludGVyYWN0aW9ucywgLi4uKXsKICAjIHRyYWluIG1vZGVsCiAgZm9ybXVsYSA8LSBnZW5lcmF0ZV9mb3JtdWxhKG1vZGVsX2NvdnMsIGxhYmVsID0gJ2lzX3JlbGVhc2UnLCBhZGRfaW50ZXJhY3Rpb25zKQogIG1vZGVsIDwtIG1hdGNoaXQoZm9ybXVsYSwgdHJhaW4sIC4uLikKICAKICAjIGV4dHJhY3QgYmV0YSBzdWJzZXQKICBkZl9tYXRjaGVkIDwtIGdldF9tYXRjaGVzKG1vZGVsLCB0cmFpbikgJT4lCiAgICBzZWxlY3QoLXdlaWdodHMsIC1kaXN0YW5jZSkgJT4lCiAgICBmaWx0ZXIobGFiZWwgPT0gJ2JldGEnKQogIAogIHJldHVybihsaXN0KG1vZGVsID0gbW9kZWwsIG1hdGNoZWQgPSBkZl9tYXRjaGVkKSkKfQoKYGBgCgojIyMgRlMgMQoKKiBgY2FsaXBlcmAgPSAwLjIwCiogYGNhbGNsb3NldGAgPSBUUlVFCiogYHJhdGlvYCA9IDIKKiBgcmVwbGFjZWAgPSBGQUxTRQoqIDR4IG92ZXJzYW1wbGluZwoKYGBge3Igbm5fbWFsX2ZzMSwgZWNobz1GQUxTRX0Kbm4ubWFsLmZzMSA8LSB0cmFpbl9tYXRjaGl0KGRmc1tbJzQnXV0sIGZzMSwgYWRkX2ludGVyYWN0aW9ucyA9IEZBTFNFLCByZXBsYWNlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICBjYWxpcGVyID0gMC4yNSwgY2FsY2xvc2VzdCA9IFRSVUUsIHJhdGlvID0gMiwgZGlzdGFuY2UgPSAibWFoYWxhbm9iaXMiKQpubi5tYWwuZnMxLnFxIDwtIGJ1aWxkX3F1YW50aWxlX2RmKGRmX3JlbF92YWwsIG5uLm1hbC5mczEkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCm5uLm1hbC5mczEuc2NvcmUgPC0gc2NvcmVfbW9kZWwoYnRzLCBubi5tYWwuZnMxJG1hdGNoZWQsIGRmX3JlbF92YWwpCm5uLm1hbC5mczEuc2NvcmUKYGBgCgpOdW1iZXIgb2YgQmV0YSBzYW1wbGVzOiBgciBucm93KG5uLm1hbC5mczEkbWF0Y2hlZClgCgpgYGB7ciBubl9tYWxfZnMxX3ZhbF9wbHQsIGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTI1LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwbG90X3ZhbGlkYXRpb25fcmVzdWx0cyhkZl9yZWxfdmFsLCBubi5tYWwuZnMxJG1hdGNoZWQsIGRmX2JldGFfdmFsLCBubi5tYWwuZnMxLnFxKQpgYGAKCiMjIyBGUyAzIAoKKiBgY2FsaXBlcmAgPSAzLjAwCiogYGNhbGNsb3NldGAgPSBUUlVFCiogYHJhdGlvYCA9IDEKKiBgcmVwbGFjZWAgPSBUUlVFCiogMTZ4IG92ZXJzYW1wbGluZwoKYGBge3Igbm5fbWFsX2ZzMywgZWNobz1GQUxTRX0Kbm4ubWFsLmZzMyA8LSB0cmFpbl9tYXRjaGl0KGRmc1tbJzE2J11dLCBmczMsIGFkZF9pbnRlcmFjdGlvbnMgPSBGQUxTRSwgcmVwbGFjZSA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICBjYWxpcGVyID0gMy4wMCwgY2FsY2xvc2VzdCA9IFRSVUUsIHJhdGlvID0gMSwgZGlzdGFuY2UgPSAibWFoYWxhbm9iaXMiKQpubi5tYWwuZnMzLnFxIDwtIGJ1aWxkX3F1YW50aWxlX2RmKGRmX3JlbF92YWwsIG5uLm1hbC5mczMkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCm5uLm1hbC5mczMuc2NvcmUgPC0gc2NvcmVfbW9kZWwoYnRzLCBubi5tYWwuZnMzJG1hdGNoZWQsIGRmX3JlbF92YWwpCm5uLm1hbC5mczMuc2NvcmUKYGBgCk51bWJlciBvZiBCZXRhIHNhbXBsZXM6IGByIG5yb3cobm4ubWFsLmZzMyRtYXRjaGVkKWAKCmBgYHtyIG5uX21hbF9mczNfdmFsX3BsdCwgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CnBsb3RfdmFsaWRhdGlvbl9yZXN1bHRzKGRmX3JlbF92YWwsIG5uLm1hbC5mczMkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCmBgYAoKCgojIyMgRlMgNQoKKiBgY2FsaXBlcmAgPSAwCiogYGNhbGNsb3NldGAgPSBUUlVFCiogYHJhdGlvYCA9IDEKKiBgcmVwbGFjZWAgPSBGQUxTRQoqIDh4IG92ZXJzYW1wbGluZwoKYGBge3Igbm5fbWFsX2ZzNSwgZWNobz1GQUxTRX0Kbm4ubWFsLmZzNSA8LSB0cmFpbl9tYXRjaGl0KGRmc1tbJzgnXV0sIGZzNSwgYWRkX2ludGVyYWN0aW9ucyA9IEZBTFNFLCByZXBsYWNlID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGlwZXIgPSAwLCBjYWxjbG9zZXN0ID0gVFJVRSwgcmF0aW8gPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgZGlzdGFuY2UgPSAibWFoYWxhbm9iaXMiKQpubi5tYWwuZnM1LnFxIDwtIGJ1aWxkX3F1YW50aWxlX2RmKGRmX3JlbF92YWwsIG5uLm1hbC5mczUkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCm5uLm1hbC5mczUuc2NvcmUgPC0gc2NvcmVfbW9kZWwoYnRzLCBubi5tYWwuZnM1JG1hdGNoZWQsIGRmX3JlbF92YWwpCm5uLm1hbC5mczUuc2NvcmUKYGBgCgpOdW1iZXIgb2YgQmV0YSBzYW1wbGVzOiBgciBucm93KG5uLm1hbC5mczUkbWF0Y2hlZClgCgpgYGB7ciBubl9tYWxfZnM1X3ZhbF9wbHQsIGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTI1LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwbG90X3ZhbGlkYXRpb25fcmVzdWx0cyhkZl9yZWxfdmFsLCBubi5tYWwuZnM1JG1hdGNoZWQsIGRmX2JldGFfdmFsKQpgYGAKCiMjIE5lYXJlc3QtTmVpZ2hib3JzIExvZ2l0LCBMaW5lYXIKCkh5cGVycGFyYW1ldGVyczogYGh5cGVycGFyYW1ldGVyX3R1bmluZ19ubl9sb2dpdF9saW5lYXIuUm1kYAoKYGBge3IgZmVhdHVyZV9zZXRzX25uLCBlY2hvPUZBTFNFfQojIFJlbG9hZCB0byBhZGQgYWRkaXRpb25hbCBjYXRlZ29yaWNhbCBjb3ZhcmlhdGVzCgpwZXJmX21ldHJpY3MgPC0gbmFtZXMoZ2V0X20yX21ldHJpY19tYXAoKSkKCmNvdnMgPC0gZGZfdHJhaW5fZiAlPiUKICBzZWxlY3QoLXBlcmZfbWV0cmljcykgJT4lCiAgc2VsZWN0KC1jb250ZW50X2NyYXNoZXMpICU+JQogIHNlbGVjdCgtY2xpZW50X2lkKSAlPiUKICBzZWxlY3QoLWxhYmVsKSAlPiUKICBzZWxlY3QoLWlzX3JlbGVhc2UpICU+JQogIHNlbGVjdCgtYXBwX3ZlcnNpb24pICU+JQogIG5hbWVzKCkKCmZzMSA8LSBwZXJmX21ldHJpY3MKZnMyIDwtIGMobmFtZXMoZnMxKSwgZmVhdHVyZXNfdG9wMTApCmZzMyA8LSBjKG5hbWVzKGZzMSksIGZlYXR1cmVzX3RvcDEwX2VxKQpmczQgPC0gYyhuYW1lcyhmczEpLCBjb3ZzKQpmczUgPC0gZmVhdHVyZXNfdG9wMTAKZnM2IDwtIGZlYXR1cmVzX3RvcDEwX2VxCmZzNyA8LSBjb3ZzCmBgYAoKIyMjIEZTIDEKCiogYGNhbGlwZXJgID0gMC40CiogYGNhbGNsb3NldGAgPSBUUlVFCiogYHJhdGlvYCA9IDMKKiBgcmVwbGFjZWAgPSBGQUxTRQoqIDR4IG92ZXJzYW1wbGluZwoqIEludGVyYWN0aW9ucyBhY3Jvc3MgY292YXJpYXRlcwoKYGBge3Igbm5fbG9naXRfZnMxLCB3YXJuaW5nPUZBTFNFLCBlcnJvcj1GQUxTRSwgZWNobz1GQUxTRX0Kbm4ubGluZWFyLmxvZ2l0LmZzMSA8LSB0cmFpbl9tYXRjaGl0KGRmc1tbJzQnXV0sIGZzMSwgYWRkX2ludGVyYWN0aW9ucyA9IFRSVUUsIHJlcGxhY2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGlwZXIgPSAwLjQsIGNhbGNsb3Nlc3QgPSBUUlVFLCByYXRpbyA9IDMsIGRpc3RhbmNlID0gImxpbmVhci5sb2dpdCIpCm5uLmxpbmVhci5sb2dpdC5mczEucXEgPC0gYnVpbGRfcXVhbnRpbGVfZGYoZGZfcmVsX3ZhbCwgbm4ubGluZWFyLmxvZ2l0LmZzMSRtYXRjaGVkLCBkZl9iZXRhX3ZhbCkKbm4ubGluZWFyLmxvZ2l0LmZzMS5zY29yZSA8LSBzY29yZV9tb2RlbChidHMsIG5uLmxpbmVhci5sb2dpdC5mczEkbWF0Y2hlZCwgZGZfcmVsX3ZhbCkKbm4ubGluZWFyLmxvZ2l0LmZzMS5zY29yZQpgYGAKCk51bWJlciBvZiBCZXRhIHNhbXBsZXM6IGByIG5yb3cobm4ubGluZWFyLmxvZ2l0LmZzMSRtYXRjaGVkKWAKCmBgYHtyIG5uX2xvZ2l0X2ZzMV92YWxfcGx0LCBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0yNSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KcGxvdF92YWxpZGF0aW9uX3Jlc3VsdHMoZGZfcmVsX3ZhbCwgbm4ubGluZWFyLmxvZ2l0LmZzMSRtYXRjaGVkLCBkZl9iZXRhX3ZhbCkKYGBgCgojIyMgRlMgNQoKKiBgY2FsaXBlcmAgPSAwCiogYGNhbGNsb3NldGAgPSBGQUxTRQoqIGByYXRpb2AgPSAxCiogYHJlcGxhY2VgID0gRkFMU0UKKiA4eCBvdmVyc2FtcGxpbmcKCmBgYHtyIG5uX2xvZ2l0X2ZzMywgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0V9Cm5uLmxpbmVhci5sb2dpdC5mczUgPC0gdHJhaW5fbWF0Y2hpdChkZnNbWyc4J11dLCBmczUsIGFkZF9pbnRlcmFjdGlvbnMgPSBGQUxTRSwgcmVwbGFjZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgY2FsaXBlciA9IDAsIGNhbGNsb3Nlc3QgPSBGQUxTRSwgcmF0aW8gPSAxLCBkaXN0YW5jZSA9ICJsaW5lYXIubG9naXQiKQpubi5saW5lYXIubG9naXQuZnM1LnFxIDwtIGJ1aWxkX3F1YW50aWxlX2RmKGRmX3JlbF92YWwsIG5uLmxpbmVhci5sb2dpdC5mczUkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCm5uLmxpbmVhci5sb2dpdC5mczUuc2NvcmUgPC0gc2NvcmVfbW9kZWwoYnRzLCBubi5saW5lYXIubG9naXQuZnM1JG1hdGNoZWQsIGRmX3JlbF92YWwpCm5uLmxpbmVhci5sb2dpdC5mczUuc2NvcmUKYGBgCgpgYGB7ciBubl9sb2dpdF9mczVfdmFsX3BsdCwgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CnBsb3RfdmFsaWRhdGlvbl9yZXN1bHRzKGRmX3JlbF92YWwsIG5uLmxpbmVhci5sb2dpdC5mczUkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCmBgYAoKIyMgTmVhcmVzdC1OZWlnaGJvcnMgR0FNLCBMb2dpdAoKSHlwZXJwYXJhbWV0ZXJzOiBgaHlwZXJwYXJhbWV0ZXJfdHVuaW5nX25uX2dhbV9sb2dpdC5SbWRgCgojIyMgRlMgMQoKKiBgY2FsaXBlcmAgPSAwLjUKKiBgY2FsY2xvc2V0YCA9IEZBTFNFCiogYHJhdGlvYCA9IDMKKiBgcmVwbGFjZWAgPSBGQUxTRQoqIDR4IG92ZXJzYW1wbGluZwoqIEludGVyYWN0aW9ucyBhY3Jvc3MgY292YXJpYXRlcwoKYGBge3Igbm5fZ2FtX2ZzMSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cm5uLmdhbS5mczEgPC0gdHJhaW5fbWF0Y2hpdChkZnNbWyc0J11dLCBmczEsIGFkZF9pbnRlcmFjdGlvbnMgPSBUUlVFLCByZXBsYWNlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICBjYWxpcGVyID0gMC41LCBjYWxjbG9zZXN0ID0gVFJVRSwgcmF0aW8gPSAzLCBkaXN0YW5jZSA9ICJHQU1sb2dpdCIpCm5uLmdhbS5mczEucXEgPC0gYnVpbGRfcXVhbnRpbGVfZGYoZGZfcmVsX3ZhbCwgbm4uZ2FtLmZzMSRtYXRjaGVkLCBkZl9iZXRhX3ZhbCkKbm4uZ2FtLmZzMS5zY29yZSA8LSBzY29yZV9tb2RlbChidHMsIG5uLmdhbS5mczEkbWF0Y2hlZCwgZGZfcmVsX3ZhbCkKbm4uZ2FtLmZzMS5zY29yZQpgYGAKCk51bWJlciBvZiBCZXRhIHNhbXBsZXM6IGByIG5yb3cobm4uZ2FtLmZzMSRtYXRjaGVkKWAKCmBgYHtyIG5uX2dhbV9mczFfdmFsX3BsdCwgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CnBsb3RfdmFsaWRhdGlvbl9yZXN1bHRzKGRmX3JlbF92YWwsIG5uLmdhbS5mczEkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCmBgYAoKCiMjIyBGUyA1CgoqIGBjYWxpcGVyYCA9IDAKKiBgY2FsY2xvc2V0YCA9IEZBTFNFCiogYHJhdGlvYCA9IDEKKiBgcmVwbGFjZWAgPSBGQUxTRQoqIDR4IG92ZXJzYW1wbGluZwoKYGBge3Igbm5fZ2FtX2ZzNSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0V9Cm5uLmdhbS5mczUgPC0gdHJhaW5fbWF0Y2hpdChkZnNbWyc0J11dLCBmczUsIGFkZF9pbnRlcmFjdGlvbnMgPSBGQUxTRSwgcmVwbGFjZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgY2FsaXBlciA9IDAsIGNhbGNsb3Nlc3QgPSBGQUxTRSwgcmF0aW8gPSAxLCBkaXN0YW5jZSA9ICJHQU1sb2dpdCIpCm5uLmdhbS5mczUucXEgPC0gYnVpbGRfcXVhbnRpbGVfZGYoZGZfcmVsX3ZhbCwgbm4uZ2FtLmZzNSRtYXRjaGVkLCBkZl9iZXRhX3ZhbCkKbm4uZ2FtLmZzNS5zY29yZSA8LSBzY29yZV9tb2RlbChidHMsIG5uLmdhbS5mczUkbWF0Y2hlZCwgZGZfcmVsX3ZhbCkKbm4uZ2FtLmZzNS5zY29yZQpgYGAKCk51bWJlciBvZiBCZXRhIHNhbXBsZXM6IGByIG5yb3cobm4uZ2FtLmZzMSRtYXRjaGVkKWAKCmBgYHtyIG5uX2dhbV9mczVfdmFsX3BsdCwgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CnBsb3RfdmFsaWRhdGlvbl9yZXN1bHRzKGRmX3JlbF92YWwsIG5uLmdhbS5mczUkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCmBgYAoKIyMgTmVhcmVzdC1OZWlnaGJvcnMgUHJvYml0LCBMaW5lYXIKCkh5cGVycGFyYW1ldGVyczogYGh5cGVycGFyYW1ldGVyX3R1bmluZ19ubl9wcm9iaXRfbGluZWFyLlJtZGAKCiMjIyBGUyAxCgoqIGBjYWxpcGVyYCA9IDAuNAoqIGBjYWxjbG9zZXRgID0gRkFMU0UKKiBgcmF0aW9gID0gMwoqIGByZXBsYWNlYCA9IEZBTFNFCiogNHggb3ZlcnNhbXBsaW5nCiogSW50ZXJhY3Rpb25zIGFjcm9zcyBjb3ZhcmlhdGVzCgpgYGB7ciBubl9wcm9iaXRfZnMxLCB3YXJuaW5nPUZBTFNFLCBlcnJvcj1GQUxTRSwgZWNobz1GQUxTRX0Kbm4ubGluZWFyLnByb2JpdC5mczEgPC0gdHJhaW5fbWF0Y2hpdChkZnNbWyc0J11dLCBmczEsIGFkZF9pbnRlcmFjdGlvbnMgPSBUUlVFLCByZXBsYWNlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICBjYWxpcGVyID0gMC40LCBjYWxjbG9zZXN0ID0gVFJVRSwgcmF0aW8gPSAzLCBkaXN0YW5jZSA9ICJsaW5lYXIucHJvYml0IikKbm4ubGluZWFyLnByb2JpdC5mczEucXEgPC0gYnVpbGRfcXVhbnRpbGVfZGYoZGZfcmVsX3ZhbCwgbm4ubGluZWFyLnByb2JpdC5mczEkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCm5uLmxpbmVhci5wcm9iaXQuZnMxLnNjb3JlIDwtIHNjb3JlX21vZGVsKGJ0cywgbm4ubGluZWFyLnByb2JpdC5mczEkbWF0Y2hlZCwgZGZfcmVsX3ZhbCkKbm4ubGluZWFyLnByb2JpdC5mczEuc2NvcmUKYGBgCgpOdW1iZXIgb2YgQmV0YSBzYW1wbGVzOiBgciBucm93KG5uLmxpbmVhci5wcm9iaXQuZnMxJG1hdGNoZWQpYAoKYGBge3Igbm5fcHJvYml0X2ZzMV92YWxfcGx0LCBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0yNSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KcGxvdF92YWxpZGF0aW9uX3Jlc3VsdHMoZGZfcmVsX3ZhbCwgbm4ubGluZWFyLnByb2JpdC5mczEkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCmBgYAoKIyMjIEZTIDUKCiogYGNhbGlwZXJgID0gMAoqIGBjYWxjbG9zZXRgID0gRkFMU0UKKiBgcmF0aW9gID0gMQoqIGByZXBsYWNlYCA9IEZBTFNFCiogOHggb3ZlcnNhbXBsaW5nCgpgYGB7ciBubl9wcm9iaXRfZnM1LCB3YXJuaW5nPUZBTFNFLCBlcnJvcj1GQUxTRSwgZWNobz1GQUxTRX0Kbm4ubGluZWFyLnByb2JpdC5mczUgPC0gdHJhaW5fbWF0Y2hpdChkZnNbWyc4J11dLCBmczUsIGFkZF9pbnRlcmFjdGlvbnMgPSBGQUxTRSwgcmVwbGFjZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgY2FsaXBlciA9IDAsIGNhbGNsb3Nlc3QgPSBGQUxTRSwgcmF0aW8gPSAxLCBkaXN0YW5jZSA9ICJsaW5lYXIucHJvYml0IikKbm4ubGluZWFyLnByb2JpdC5mczUucXEgPC0gYnVpbGRfcXVhbnRpbGVfZGYoZGZfcmVsX3ZhbCwgbm4ubGluZWFyLnByb2JpdC5mczUkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCm5uLmxpbmVhci5wcm9iaXQuZnM1LnNjb3JlIDwtIHNjb3JlX21vZGVsKGJ0cywgbm4ubGluZWFyLnByb2JpdC5mczUkbWF0Y2hlZCwgZGZfcmVsX3ZhbCkKbm4ubGluZWFyLnByb2JpdC5mczUuc2NvcmUKYGBgCgpOdW1iZXIgb2YgQmV0YSBzYW1wbGVzOiBgciBucm93KG5uLmxpbmVhci5wcm9iaXQuZnM1JG1hdGNoZWQpYAoKYGBge3Igbm5fcHJvYml0X2ZzNV92YWxfcGx0LCBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0yNSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KcGxvdF92YWxpZGF0aW9uX3Jlc3VsdHMoZGZfcmVsX3ZhbCwgbm4ubGluZWFyLnByb2JpdC5mczUkbWF0Y2hlZCwgZGZfYmV0YV92YWwpCmBgYAoKIyMgR2VuZXRpYyBNYXRjaGluZwoKRHVlIHRvIHRoZSB2ZXJ5IGxvbmcgdHJhaW5pbmcgdGltZXMgb2YgZ2VuZXRpYyBtYXRjaGluZywgZmVhdHVyZSBzZWxlY3Rpb24gYW5kIGh5cGVycGFyYW1ldGVyIHR1bmluZyB3ZXJlIG5vdCBwZXJmb3JtZWQgdXNpbmcgYm9vdHN0cmFwIHNhbXBlcy4gVGhlIG1vZGVscyB3ZXJlIHByZXZpb3VzbHkgdHJhaW5lZCB1c2luZyB0aGUgZnVsbCB0cmFpbmluZyBzYW1wbGUuIFRoZSByZXN1bHRhbnQgbWF0Y2ggYmV0YSBzdWJzZXRzIHdlcmUgc2VyaWFsaXplZCBhbmQgdXBsb2FkZWQgdG8gR0NQLgoKVHJhaW5lZDogYGZlYXR1cmVfc2VsZWN0aW9uX2dlbm1hdGNoX2xpbmVhci5SbWRgCgpgYGB7ciBnZW5tYXRjaCwgZWNobz1GQUxTRSwgZXJyb3I9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmZpbGVfbmFtZSA9ICdmZWF0dXJlX3NlbGVjdGlvbl9nZW5tYXRjaF8uUkRhdGEnCmltYWdlX2ZpbGVfcGF0aCA9IGZpbGUucGF0aCgnZGF0YScsIGZpbGVfbmFtZSkKCiMgUHVsbCBmcm9tIEdDUCBpZiBuZWNlc3NhcnkKaWYgKCFmaWxlLmV4aXN0cyhpbWFnZV9maWxlX3BhdGgpKXsKICBTeXMuc2V0ZW52KCJHQ1NfREVGQVVMVF9CVUNLRVQiID0gIm1vei1meC1kZXYtc3ViYmV0YSIsCiAgICAgICAgICAgIkdDU19BVVRIX0ZJTEUiID0gIm1vei1meC1kZXYtY2Rvd2h5Z2x1bmQtc3ViQmV0YS03ODhmOGYwZDQ2MjcuanNvbiIpCiAgbGlicmFyeShnb29nbGVDbG91ZFN0b3JhZ2VSKQogIGdjc19nZXRfb2JqZWN0KGZpbGUucGF0aCgnZGF0YScsICdtaWxlc3RvbmUyJywgZmlsZV9uYW1lKSwgc2F2ZVRvRGlzayA9IGltYWdlX2ZpbGVfcGF0aCwgb3ZlcndyaXRlID0gVFJVRSkKCn0KbG9hZChpbWFnZV9maWxlX3BhdGgpCmBgYAoKIyMjIEZTIDEKCmBgYHtyIGdlbm1hdGNoX2ZzMSwgZWNobz1GQUxTRX0KZ2VubWF0Y2guZnMxLm1hdGNoZWQgPC0gZGZfdHJhaW5fZ2VuW2ZzMV9yZXN1bHRzJG1hdGNoZXMkaW5kZXguY29udHJvbCxdCmdlbm1hdGNoLmZzMS5xcSA8LSBidWlsZF9xdWFudGlsZV9kZihkZl9yZWxfdmFsLCBnZW5tYXRjaC5mczEubWF0Y2hlZCwgZGZfYmV0YV92YWwpCmdlbm1hdGNoLmZzMS5zY29yZSA8LSBzY29yZV9tb2RlbChidHMsIGdlbm1hdGNoLmZzMS5tYXRjaGVkLCBkZl9yZWxfdmFsKQpnZW5tYXRjaC5mczEuc2NvcmUKYGBgCgpOdW1iZXIgb2YgQmV0YSBzYW1wbGVzOiBgciBucm93KGdlbm1hdGNoLmZzMS5tYXRjaGVkKWAKCmBgYHtyIGdlbm1hdGNoX2ZzMV92YWxfcGx0LCBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0yNSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KcGxvdF92YWxpZGF0aW9uX3Jlc3VsdHMoZGZfcmVsX3ZhbCwgZ2VubWF0Y2guZnMxLm1hdGNoZWQsIGRmX2JldGFfdmFsKQpgYGAKCiMjIyMgUG9wLlNpemUgNTAwCgpgYGB7ciBnZW5tYXRjaF9mczFfNTAwLCBlY2hvPUZBTFNFfQpnZW5tYXRjaC5mczEuNTAwLm1hdGNoZWQgPC0gZGZfdHJhaW5fZ2VuW2ZzMV81MDBfcmVzdWx0cyRtYXRjaGVzJGluZGV4LmNvbnRyb2wsXQpnZW5tYXRjaC5mczEuNTAwLnFxIDwtIGJ1aWxkX3F1YW50aWxlX2RmKGRmX3JlbF92YWwsIGdlbm1hdGNoLmZzMS41MDAubWF0Y2hlZCwgZGZfYmV0YV92YWwpCmdlbm1hdGNoLmZzMS41MDAuc2NvcmUgPC0gc2NvcmVfbW9kZWwoYnRzLCBnZW5tYXRjaC5mczEuNTAwLm1hdGNoZWQsIGRmX3JlbF92YWwpCmdlbm1hdGNoLmZzMS41MDAuc2NvcmUKYGBgCgpOdW1iZXIgb2YgQmV0YSBzYW1wbGVzOiBgciBucm93KGdlbm1hdGNoLmZzMS41MDAubWF0Y2hlZClgCgpgYGB7ciBnZW5tYXRjaF9mczFfNTAwX3ZhbF9wbHQsIGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTI1LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwbG90X3ZhbGlkYXRpb25fcmVzdWx0cyhkZl9yZWxfdmFsLCBnZW5tYXRjaC5mczEuNTAwLm1hdGNoZWQsIGRmX2JldGFfdmFsKQpgYGAKCgojIyMgRlMgMwoKYGBge3IgZ2VubWF0Y2hfZnMzLCBlY2hvPUZBTFNFfQpnZW5tYXRjaC5mczMubWF0Y2hlZCA8LSBkZl90cmFpbl9nZW5bZnMzX3Jlc3VsdHMkbWF0Y2hlcyRpbmRleC5jb250cm9sLF0KZ2VubWF0Y2guZnMzLnFxIDwtIGJ1aWxkX3F1YW50aWxlX2RmKGRmX3JlbF92YWwsIGdlbm1hdGNoLmZzMy5tYXRjaGVkLCBkZl9iZXRhX3ZhbCkKZ2VubWF0Y2guZnMzLnNjb3JlIDwtIHNjb3JlX21vZGVsKGJ0cywgZ2VubWF0Y2guZnMzLm1hdGNoZWQsIGRmX3JlbF92YWwpCmdlbm1hdGNoLmZzMy5zY29yZQpgYGAKCk51bWJlciBvZiBCZXRhIHNhbXBsZXM6IGByIG5yb3coZ2VubWF0Y2guZnMzLm1hdGNoZWQpYAoKYGBge3IgZ2VubWF0Y2hfZnMzX3ZhbF9wbHQsIGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTI1LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwbG90X3ZhbGlkYXRpb25fcmVzdWx0cyhkZl9yZWxfdmFsLCBnZW5tYXRjaC5mczMubWF0Y2hlZCwgZGZfYmV0YV92YWwpCmBgYAoKIyMjIEZTIDUKCmBgYHtyIGdlbm1hdGNoX2ZzNSwgZWNobz1GQUxTRX0KZ2VubWF0Y2guZnM1Lm1hdGNoZWQgPC0gZGZfdHJhaW5fZ2VuW2ZzNV9yZXN1bHRzJG1hdGNoZXMkaW5kZXguY29udHJvbCxdCmdlbm1hdGNoLmZzNS5xcSA8LSBidWlsZF9xdWFudGlsZV9kZihkZl9yZWxfdmFsLCBnZW5tYXRjaC5mczUubWF0Y2hlZCwgZGZfYmV0YV92YWwpCmdlbm1hdGNoLmZzNS5zY29yZSA8LSBzY29yZV9tb2RlbChidHMsIGdlbm1hdGNoLmZzNS5tYXRjaGVkLCBkZl9yZWxfdmFsKQpnZW5tYXRjaC5mczUuc2NvcmUKYGBgCgpOdW1iZXIgb2YgQmV0YSBzYW1wbGVzOiBgciBucm93KGdlbm1hdGNoLmZzMy5tYXRjaGVkKWAKCmBgYHtyIGdlbm1hdGNoX2ZzNV92YWxfcGx0LCBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0yNSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KcGxvdF92YWxpZGF0aW9uX3Jlc3VsdHMoZGZfcmVsX3ZhbCwgZ2VubWF0Y2guZnM1Lm1hdGNoZWQsIGRmX2JldGFfdmFsKQpgYGAKCiMgUmVzdWx0cwoKR2VuZXRpYyBtYXRjaGluZyBwcm9kdWNlcyB0aGUgb3B0aW1hbCBtYXRjaGluZyByZXN1bHRzLiBJdCB5aWVsZHMgdGhlIGxvd2VzdCBzY29yZXMsIHdpdGhvdXQgZHJvcHBpbmcgbGFyZ2Ugc2FtcGxlIG9mIHRoZSBCZXRhIHByb2ZpbGVzLiBVbnN1cnByaXNpbmdseSwgbWF0Y2hpbmcgZGlyZWN0bHksIGFuZCBvbmx5LCBvbiB0aGUgcGVyZm9ybWFuY2UgbWV0cmljcyB5aWVsZHMgdGhlIGJlc3QgcmVzdWx0cy4gSW5jcmVhc2luZyB0aGUgcG9wdWxhdGlvbiBzaXplIGh5cGVycGFyYW1ldGVyIHNsaWdodGx5IGRlY3JlYXNlZCBtb2RlbCBwZXJmb3JtYW5jZSwgd2hpY2ggaXMgc3VycHJpc2luZy4gQ29uc2lkZXJpbmcgdGhpcyBzdWJzdGFudGlhbGx5IGluY3JlYXNlcyB0cmFpbmluZyB0aW1lcywgdGhlIGxvd2VyIHZhbHVlIHdpbGwgYmUgdXNlZC4gCgoqKkNvbmNsdXNpb24qKjogT3B0aW1hbCBtb2RlbCBmcmFtZXdvcmsKCiogbWF0Y2hpbmcgYWxnb3JpdGhtOiBHZW5ldGljIE1hdGNoaW5nCiogZmVhdHVyZXM6IE9ubHkgcGVyZm9ybWFuY2UgbWV0cmljcwoqIGh5cGVycGFyYW1ldGVyczogRGVmYXVsdCBmb3IgYE1hdGNoaW5nYCBsaWJyYXJ5CgojIFB1c2ggdG8gR0NQCgpUaGUgYm9vc3RyYXAgcmVwbGljYXRlcyBmb3IgdmFsaWRhdGlvbiwgb3ZlcnNhbXBsZWQgdHJhaW5pbmlnIGRhdGFzZXRzLCByZXN1bHRhbnQgcXVhbnRpbGUgY2FsY3VsYXRpb25zLCBhbmQgbWF0Y2hlZCBkYXRhc2V0cyBhcmUgc2F2ZWQgdG8gYW4gUiBpbWFnZS4gVGhlbiB1cGxvYWRlZCB0byB0aGUgcHJvamVjdCBHQ1AgYnVja2V0LgoKYGBge3Igc2VyaWFsaXplX2djcCwgZWNobz1GQUxTRX0KcmVzdWx0c19maWxlX25hbWUgPSAndmFsaWRhdGlvbl9yZXN1bHRzXzIwMTkxMTA2LlJEYXRhJwpyZXN1bHRzX2ZpbGVfcGF0aCA9IGZpbGUucGF0aCgnZGF0YScsIHJlc3VsdHNfZmlsZV9uYW1lKQoKb2JqZWN0cyA8LSBjKAogIGxzKHBhdHRlcm4gPSAnZ2VubWF0Y2gnKSwKICBscyhwYXR0ZXJuID0gJ25uJyksCiAgbHMocGF0dGVybiA9ICdeYnRzJCcpLAogIGxzKHBhdHRlcm4gPSAnXmRmcyQnKQopCgpzYXZlKGxpc3QgPSBvYmplY3RzLCBmaWxlID0gcmVzdWx0c19maWxlX3BhdGgpCmBgYAoKCmBgYHtyIHB1c2hfdG9fZ2NwLCBlY2hvPUZBTFNFfQpnY3NfZmlsZV9wYXRoIDwtIGZpbGUucGF0aCgnZGF0YScsICdtaWxlc3RvbmUyJywgcmVzdWx0c19maWxlX25hbWUpCgpTeXMuc2V0ZW52KCJHQ1NfREVGQVVMVF9CVUNLRVQiID0gIm1vei1meC1kZXYtc3ViYmV0YSIsCiAgICAgICAgICAgIkdDU19BVVRIX0ZJTEUiID0gIm1vei1meC1kZXYtY2Rvd2h5Z2x1bmQtc3ViQmV0YS03ODhmOGYwZDQ2MjcuanNvbiIpCgpsaWJyYXJ5KGdvb2dsZUNsb3VkU3RvcmFnZVIpCgpwcm9qX2ZpbGVzID0gZ2NzX2xpc3Rfb2JqZWN0cygpCgppZiAoZ2NzX2ZpbGVfcGF0aCAlaW4lIHByb2pfZmlsZXMkbmFtZSkgewogIHByaW50KHBhc3RlKCdQcmV2aW91c2x5IHRyYWluZWQgcmVzdWx0cyBhbHJlYWR5IGV4aXN0OicsIGdjc19maWxlX3BhdGgpKQp9IGVsc2UgewogIHByaW50KHBhc3RlKCdVcGxvYWRpbmcgdmFsaWRhdGlvbiByZXN1bHRzIHRvIEdDUDonLCBnY3NfZmlsZV9wYXRoKSkKICB1cGxvYWRfdHJ5IDwtIGdjc191cGxvYWQocmVzdWx0c19maWxlX3BhdGgsIG5hbWUgPSBnY3NfZmlsZV9wYXRoKQogIHVwbG9hZF90cnkKfQpgYGAKCgoK